﻿using System;
using System.Collections;

namespace Core.Tools
{
    /// <summary>
    /// 多维数组的 IList 接口
    /// </summary>
    public abstract class BaseMultidimensionalArrayList : IList
    {
        public abstract object this[int index] { get; set; }

        public bool IsReadOnly { get { return false; } }

        public bool IsFixedSize { get { return true; } }

        public abstract int Count { get; }

        public object SyncRoot { get { return null; } }

        public bool IsSynchronized { get { return false; } }

        public int Add(object value)
        {
            throw new NotSupportedException("Is fixed size.");
        }

        public void Clear()
        {
            throw new NotSupportedException("Is fixed size.");
        }

        public bool Contains(object value)
        {
            return IndexOf(value) != -1;
        }

        public void CopyTo(Array array, int index)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }

            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            int Length = array.Length - index;

            if (Length < Count)
            {
                throw new ArgumentException("Length");
            }

            if (array.Rank != 1)
            {
                throw new ArgumentException("Rank");
            }

            foreach (var Item in this)
            {
                array.SetValue(Item, index);
                ++index;
            }
        }

        public IEnumerator GetEnumerator()
        {
            return new CollectionEnumerator<object>(Index => { return this[Index]; }, Count, true);
        }

        public int IndexOf(object value)
        {
            if (value == null)
            {
                for (int i = 0; i < Count; i++)
                {
                    if (this[i] == null)
                    {
                        return i;
                    }
                }
            }
            else
            {
                for (int i = 0; i < Count; i++)
                {
                    if (value.Equals(this[i]))
                    {
                        return i;
                    }
                }
            }

            return -1;
        }

        public void Insert(int index, object value)
        {
            if (index < Count)
            {
                this[index] = value;
            }
            else
            {
                throw new NotSupportedException("Is fixed size.");
            }
        }

        public void Remove(object value)
        {
            throw new NotSupportedException("Is fixed size.");
        }

        public void RemoveAt(int index)
        {
            throw new NotSupportedException("Is fixed size.");
        }

        internal abstract object InternalGetValue(int[] Index);

        internal abstract void InternalSetValue(int[] Index, object Value);

        public abstract Type ElementType { get; }
    }

    /// <summary>
    /// 多维数组的 IList 接口
    /// </summary>
    public class MultidimensionalArrayList : BaseMultidimensionalArrayList
    {
        public readonly Array Content;

        /// <summary>
        /// 初始化多维数组的 IList 接口
        /// </summary>
        public MultidimensionalArrayList(Array Content)
        {
            if (Content == null)
            {
                throw new NullReferenceException("Content");
            }

            this.Content = Content;
        }

        public override object this[int Index]
        {
            get
            {
                if (Content.Rank == 1)
                {
                    return Content.GetValue(Index);
                }

                return new Children(this, this, 1, Index);
            }
            set
            {
                if (Content.Rank == 1)
                {
                    Content.SetValue(value, Index);

                    return;
                }

                if (Index >= 0 && Index < Count && value is Children)
                {
                    var ChildrenValue = (Children)value;

                    if (ChildrenValue.Base == this || Index == ChildrenValue.Index && ChildrenValue.Rank == 1)
                    {
                        return;
                    }
                }

                throw new Exception("多维数组不能修改非最后一维的元素。");
            }
        }

        public override int Count
        {
            get
            {
                return InternalGetLength(0);
            }
        }

        internal Type GetElementType(int Rank)
        {
            if (Content.Rank == Rank)
            {
                return Content.GetType().GetElementType();
            }

            return typeof(Children);
        }

        public override Type ElementType { get { return GetElementType(1); } }

        internal override object InternalGetValue(int[] Index)
        {
            return Content.GetValue(Index);
        }

        internal int InternalGetLength(int Rank)
        {
            return Content.GetLength(Rank);
        }

        internal bool IsLastRank(int Rank)
        {
            return Content.Rank == Rank;
        }

        internal override void InternalSetValue(int[] Index, object Value)
        {
            Content.SetValue(Value, Index);
        }

        public class Children : BaseMultidimensionalArrayList
        {
            public Children(MultidimensionalArrayList Root, BaseMultidimensionalArrayList Base, int Rank, int Index)
            {
                this.Root = Root;
                this.Base = Base;
                this.Rank = Rank;
                this.Index = Index;
            }

            internal readonly MultidimensionalArrayList Root;
            internal readonly BaseMultidimensionalArrayList Base;
            internal readonly int Rank;
            internal readonly int Index;

            public override object this[int Index]
            {
                get
                {
                    int Length = Rank + 1;

                    if (Root.IsLastRank(Length))
                    {
                        var ArrayIndex = new int[Length];

                        ArrayIndex[Rank] = Index;

                        return InternalGetValue(ArrayIndex);
                    }

                    return new Children(Root, this, Rank + 1, Index);
                }
                set
                {
                    int Length = Rank + 1;

                    if (Root.IsLastRank(Length))
                    {
                        var ArrayIndex = new int[Length];

                        ArrayIndex[Rank] = Index;

                        InternalSetValue(ArrayIndex, value);

                        return;
                    }

                    if (Index >= 0 && Index < Count && value is Children)
                    {
                        var ChildrenValue = (Children)value;

                        if (ChildrenValue.Base == this || Index == ChildrenValue.Index && ChildrenValue.Rank == Length)
                        {
                            return;
                        }
                    }

                    throw new Exception("多维数组不能修改非最后一维的元素。");
                }
            }

            public override int Count { get { return Root.InternalGetLength(Rank); } }

            public override Type ElementType { get { return Root.GetElementType(Rank + 1); } }

            internal override object InternalGetValue(int[] Index)
            {
                Index[Rank - 1] = this.Index;

                return Base.InternalGetValue(Index);
            }

            internal override void InternalSetValue(int[] Index, object Value)
            {
                Index[Rank - 1] = this.Index;

                Base.InternalSetValue(Index, Value);
            }
        }
    }
}
